package com.xzx.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 *
 * @author xinzhixuan
 * @version 1.0
 * @date 2025/9/26 14:43
 */
public class NIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(9999));
        System.out.println("服务器启动成功");

        // 注册accept事件
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            // 这里会阻塞，直到有事件发生
            selector.select();
            // 这里一定能获取到事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                if (selectionKey.isAcceptable()) {
                    handleAcceptEvent(selectionKey);
                } else if (selectionKey.isReadable()) {
                    handleReadEvent(selectionKey);
                } else if (selectionKey.isWritable()) {
                    handleWriteEvent(selectionKey);
                }
                // 这个SelectionKey(事件)处理完之后，删除不然会重复处理
                iterator.remove();
            }
        }

    }

    private static void handleWriteEvent(SelectionKey selectionKey) {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        try {
            ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
            buffer.flip();
            socketChannel.write(buffer);
            System.out.println("向 " + socketChannel.getRemoteAddress() + " 发送数据：" + new String(buffer.array(), 0, buffer.limit()));
            selectionKey.interestOps(SelectionKey.OP_READ);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handleReadEvent(SelectionKey selectionKey) {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        try {
            ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
            buffer.clear();
            int len = socketChannel.read(buffer);
            if (len == -1) {
                // 客户端断开了链接
                System.out.println("客户端：" + socketChannel.getRemoteAddress() + " 断开链接");
                socketChannel.close();
            } else if (len > 0) {
                System.out.println("接收到 " + socketChannel.getRemoteAddress() + " 的数据：" + new String(buffer.array(), 0, len));
                // 感兴趣的事件切成写
                selectionKey.interestOps(SelectionKey.OP_WRITE);
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("处理读事件时发生异常，关闭连接: " + e.getMessage());
            selectionKey.cancel();
            try {
                socketChannel.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    private static void handleAcceptEvent(SelectionKey selectionKey) {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        try {
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            // 为每个连接创建一个buffer就可以了
            socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(1024));

            System.out.println("客户端：" + socketChannel.getRemoteAddress() + " 上线");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
